home *** CD-ROM | disk | FTP | other *** search
/ The Fatted Calf / The Fatted Calf.iso / Unix / CNews / Source / relay / trbatch.c < prev   
Encoding:
C/C++ Source or Header  |  1992-04-18  |  7.3 KB  |  276 lines

  1. /*
  2.  * transmit batch file management (UUNET-sized-site version; master batch files)
  3.  */
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <sys/types.h>
  7. #include "hdbm.h"
  8. #include "hash.h"
  9. #include "libc.h"
  10. #include "news.h"
  11. #include "config.h"    /* for artfile() */
  12. #include "msgs.h"
  13. #include "trbatch.h"
  14.  
  15. /* tunable parameters */
  16. #ifndef MASTERDIR
  17. #define MASTERDIR artfile("out.master")
  18. #endif            /* MASTERDIR */
  19. #ifndef NBFSPERMBF
  20. #define NBFSPERMBF 10    /* # batchfiles per master batchfile (200 for UUNET) */
  21.             /* computable with dup */
  22. #endif            /* NBFSPERMBF */
  23. #ifndef HASHFILSZ
  24. #define HASHFILSZ ((NOPENBFS*NBFSPERMBF)/2)
  25.             /* # of hash buckets for batch file names */
  26. #endif            /* HASHFILSZ */
  27.  
  28. #define MAXSLOTS (NOPENBFS*NBFSPERMBF)
  29.  
  30. /* mapping macros */
  31. #define MBORD(slot)  ((unsigned)(slot) / NBFSPERMBF) /* slot to mbf ordinal */
  32. #define MBSLOT(slot) ((unsigned)(slot) % NBFSPERMBF) /* slot to mbf subslot */
  33.  
  34. /* TODO: dynamically allocate and grow these data structures */
  35. /*
  36.  * Each "batchfile" is actually a master batch file, each of
  37.  * which contains the data needed to create up to NBFSPERMBF batch files
  38.  * (by a separate "exploder" program).  The format is
  39.  *    # optional comment line
  40.  *    <msgid> relative-path size
  41.  *    F out.going/site1/togo
  42.  *    f /usr/spool/news/out.going/site2/togo
  43.  *    n out.nntp/site3
  44.  *    I out.going/site4.wehave/togo
  45.  * where there is a <msgid> line per article and an F, f, n or I line
  46.  * per site getting that article.
  47.  *
  48.  * To avoid splitting multiple sys entries for the same site across
  49.  * master batch files, we need to hash the batch file names down to
  50.  * unique ids, which we then map to a master batch file.
  51.  */
  52. static char ordtombfs[MAXSLOTS];    /* ord -> mb ord map */
  53. static char otomvalid[MAXSLOTS];    /* above mapping valid bits */
  54.  
  55. struct hashfilename {
  56.     unsigned short hf_mbf;        /* master batch file ordinal # */
  57. };
  58. static HASHTABLE *nmordtbl;        /* name -> mbf ordinal mapping */
  59.  
  60. /* forwards */
  61. FORWARD struct batchfile *bfinstall();
  62.  
  63. /*
  64.  * open "name" for appending, for batch sys entry with ordinal # "ord".
  65.  *
  66.  * if ord is too big, see if any batchfile has been assigned to "name" yet;
  67.  * if not, set up a fake batchfile for temporary use.  if ord is in range,
  68.  * ensure that (name, ord) are mapped to a batchfile.
  69.  *
  70.  * if an attempt to open the batchfile's stream fails, close an arbitrary
  71.  * batchfile stream and retry the open.
  72.  */
  73. struct batchfile *
  74. bfopen(name, ord)
  75. register char *name;
  76. register int ord;
  77. {
  78.     register struct batchfile *bf;
  79.  
  80.     if (ord >= MAXSLOTS) {        /* no mapping possible */
  81.         /* should not get here any more */
  82.         errno = 0;
  83.         errunlock("in bfopen, ord >= MAXSLOTS", "");
  84. #ifdef notdef
  85.         bf = bfisopen(name);
  86.         if (bf == NULL)
  87.             bf = fakebf((FILE *)NULL, name);
  88. #endif
  89.     } else
  90.         bf = bfincache(name, ord);
  91.  
  92.     if (bf->bf_str == NULL) {
  93.         register char *bfname =
  94.             (bf->bf_name != NULL? bf->bf_name: "fake");
  95.  
  96.         /* TODO: may want to use popenclex here for exploders */
  97.         bf->bf_str = fopenclex(bfname, "a");    /* silent try */
  98.         if (bf->bf_str == NULL) {
  99.             if (bfrclose() != ST_OKAY)
  100.                 return NULL;
  101.             /* retry, may bitch */
  102.             bf->bf_str = fopenwclex(bfname, "a");
  103.         }
  104.         if (bf->bf_str != NULL)
  105.             bfsetup(bf);
  106.     }
  107.     return bf;
  108. }
  109.  
  110. /*
  111.  * returns a batchfile, never NULL, corresponding to name and ord.
  112.  * if ord isn't mapped, search the batchfile cache for name;
  113.  * If ord & name are unmapped; find free mbf slot, opening new mbf if needed,
  114.  * and map the name and ord.
  115.  */
  116. STATIC struct batchfile *
  117. bfincache(name, ord)
  118. register char *name;
  119. register int ord;            /* batch file ord */
  120. {
  121.     register struct batchfile *mbf;
  122.  
  123.     if (otomvalid[ord])        /* ord -> mbf mapped? */
  124.         return &batchfile[ordtombfs[ord]];
  125.  
  126.     mbf = bfisopen(name);
  127.     if (mbf == NULL) {        /* name is unmapped? */
  128.         register int slot, mbord;
  129.  
  130.         slot = ord;        /* for stability across runs */
  131.         if (slot >= MAXSLOTS) {
  132.             errno = 0;
  133.             errunlock("in bfincache, slot >= MAXSLOTS", "");
  134.         }
  135.         mbord = MBORD(slot);
  136.         mbf = &batchfile[mbord];
  137.         if (mbf->bf_name == NULL) {
  138.             /* open new mbf */
  139.             register char *mbname;
  140.             char uniq[MAXCOMP];
  141.     
  142.             (void) sprintf(uniq, "%d", mbord);
  143.             mbname = str3save(MASTERDIR, SFNDELIM, uniq);
  144.             /* establish new mapping for a new master batch file */
  145.             /* TODO: may want to name an exploder here */
  146.             mbf = bfinstall(mbname, mbord);
  147.             free(mbname);
  148.             ordtobfs[mbord] = mbf;    /* map mbord -> mbf */
  149.         }
  150.     
  151.         /* add this batch file name to the hash chain */
  152.         hfinstall(name, mbord, ord);
  153.     }
  154.  
  155.     /* set up mapping for the future */
  156.     ordtombfs[ord] = mbf - batchfile;    /* mbord */
  157.     otomvalid[ord] = YES;
  158.     /* mapping is now set (ord -> mbf) */
  159.     return mbf;
  160. }
  161.  
  162. /* establish new mapping for a new master batch file */
  163. STATIC struct batchfile *
  164. bfinstall(name, ord)
  165. int ord;
  166. char *name;
  167. {
  168.     register struct batchfile *bf = &batchfile[ord];
  169.  
  170.     if (ordtobfs[ord] != NULL || bf->bf_name != NULL) { /* already in use? */
  171.         errno = 0;
  172.         if (ordtobfs[ord] != NULL)
  173.             errunlock("in bfinstall, ordtobfs[ord] != NULL", "");
  174.         else
  175.             errunlock("in bfinstall, bf->bf_name != NULL", "");
  176.     }
  177.     ordtobfs[ord] = bf;
  178.     bf->bf_name = strsave(name);
  179.     bf->bf_str = NULL;    /* paranoia */
  180. #ifdef notdef
  181.     bf->bf_ref = 0;
  182. #endif
  183.     bf->bf_msgid = NULL;
  184.     bf->bf_lines = FLUSHEVERY;
  185.     return bf;
  186. }
  187.  
  188. /*
  189.  * write filename, message-id or size on batch file "bf".
  190.  * under the 'f' flag, include the size in bytes of the article
  191.  * after "name" to assist the C news batcher.  under the 'n' flag,
  192.  * write the article's message-id.  afterward, flush "bf" in case
  193.  * the machine crashes before the stream is closed.
  194.  * don't check putc return value for portability; use ferror.
  195.  */
  196. int                            /* boolean */
  197. bfappend(bf, flag, batname, artname, msgid, size)
  198. register struct batchfile *bf;
  199. int flag;
  200. char *batname, *artname, *msgid;
  201. long size;
  202. {
  203.     register FILE *bfstr = bf->bf_str;
  204.  
  205.     if (bf->bf_msgid == NULL || !STREQ(bf->bf_msgid, msgid)) {
  206.         /* fresh article on this master batch file */
  207.         if (fflush(bfstr) == EOF)
  208.             return NO;
  209.         nnfree(&bf->bf_msgid);
  210.         bf->bf_msgid = strsave(msgid);
  211.  
  212.         if (fputs(msgid, bfstr) == EOF)
  213.             return NO;
  214.         (void) putc(' ', bfstr);
  215.         if (fputs(artname, bfstr) == EOF)
  216.             return NO;
  217.         (void) putc(' ', bfstr);
  218.         if (fprintf(bfstr, "%ld", size) == EOF)
  219.             return NO;
  220.         (void) putc('\n', bfstr);
  221.     }
  222.  
  223.     /* data for this sys entry */
  224.     (void) putc(flag, bfstr);
  225.     (void) putc(' ', bfstr);
  226. #ifdef FULLBATCHFILENAMES
  227.     if (batname[0] != FNDELIM)
  228.         batname = fullartfile(batname);
  229. #endif
  230.     if (fputs(batname, bfstr) == EOF)
  231.         return NO;
  232.     (void) putc('\n', bfstr);
  233.     if (ferror(bfstr))
  234.         return NO;
  235.     return YES;        
  236. }
  237.  
  238. /* --- hashing --- */
  239.  
  240. /*
  241.  * search the batchfile cache for "name"; return the corresponding
  242.  * open master batch file, if any.
  243.  */
  244. STATIC struct batchfile *
  245. bfisopen(name)
  246. register char *name;
  247. {
  248.     register struct hashfilename *hf;
  249.  
  250.     if (nmordtbl == NULL)
  251.         return NULL;
  252.     hf = (struct hashfilename *)hashfetch(nmordtbl, name);
  253.     return (hf == NULL? NULL: &batchfile[hf->hf_mbf]);
  254. }
  255.  
  256. STATIC
  257. hfinstall(name, mbford, ord)
  258. char *name;
  259. int mbford, ord;
  260. {
  261.     register struct hashfilename *hf;
  262.  
  263.     if (nmordtbl == NULL)
  264.         nmordtbl = hashcreate(HASHFILSZ, (unsigned (*)())NULL);
  265.     hf = (struct hashfilename *)hashfetch(nmordtbl, name);
  266.     if (hf != NULL)
  267.         return;            /* error: name present */
  268.     /* allocate, append & initialise a new entry */
  269.     hf = (struct hashfilename *)nemalloc(sizeof *hf);
  270.     hf->hf_mbf = mbford;
  271.     if (!hashstore(nmordtbl, strsave(name), (HASHDATUM)hf))
  272.         errunlock("can't store under hash key `%s'", name);
  273.     ordtombfs[ord] = mbford;
  274.     otomvalid[ord] = YES;
  275. }
  276.